#ifndef JAM_H
#define JAM_H

#ifdef _MSC_VER
#pragma once
#endif

#include "detail/const_string.hpp"
#include "detail/concatenation.hpp"
#include "detail/io.hpp"

#include <boost/config.hpp>
#include <boost/format.hpp>
#include <boost/intrusive_ptr.hpp>
#include <stdexcept>
#include <malloc.h>

#define JAM_MAX_PARAMS 9

#if defined(BOOST_HAS_DECLSPEC) && defined(JAMLIB_SHARED)
	#ifdef BUILDING_JAMLIB
		#define JAMLIB_EXPORT __declspec(dllexport)		
	#else
		#define JAMLIB_EXPORT __declspec(dllimport)
	#endif
#else
#define JAMLIB_EXPORT
#endif

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4275) // non-dll class used as base for dll class
#pragma warning(disable: 4251) // xxx needs to have dll-interface to be used by clients of class 'yyy'
#endif

///////////////////////////////////////////////////////////////////////////////////////
////// JAM string definition
///////////////////////////////////////////////////////////////////////////////////////
typedef boost::const_string<char> jam_string;
#define TRIVIAL_STRING_BIT 2
#define NON_TRIVIAL_STRING_BIT 4

///////////////////////////////////////////////////////////////////////////////////////
////// JAM exception
///////////////////////////////////////////////////////////////////////////////////////
class JAMLIB_EXPORT jam_exception : public std::exception
{
	std::string what_;
public:
	jam_exception(const boost::format& form)
	{
		what_=form.str();
	}
	jam_exception(const std::string &str)
	{
		what_=str;
	}
	jam_exception(const char *str)
	{
		what_=str;
	}
	jam_exception(const jam_string &str)
	{
		what_=str.c_str();
	}
	const char* what() const throw()
	{
		return what_.c_str();
	}

	virtual ~jam_exception() throw()
	{
	}
};

///////////////////////////////////////////////////////////////////////////////////////
////// PTR utils
///////////////////////////////////////////////////////////////////////////////////////
struct ref_count_holder
{
	mutable int ref_count_;
	int initial_count_;

	ref_count_holder(int initial_count=0) : 
		ref_count_(initial_count), initial_count_(initial_count) {}
	ref_count_holder(const ref_count_holder &oth) : 
		ref_count_(oth.initial_count_){}

protected:
	~ref_count_holder(){}; //Disallow virtual destruction
};

#define DECLARE_INTRUSIVE_PTR(typename) DECLARE_INTRUSIVE_NAMED_PTR(typename,typename)

#define DECLARE_INTRUSIVE_NAMED_PTR(typename,ptr_base_name) \
inline void intrusive_ptr_add_ref(typename * p) \
{ \
	p->ref_count_++; \
} \
inline void intrusive_ptr_release(typename * p) \
{ \
	assert(p->ref_count_); \
	if (--(p->ref_count_)==0) \
		delete p; \
} \
inline void intrusive_ptr_add_ref(const typename * p) \
{ \
	p->ref_count_++; \
} \
inline void intrusive_ptr_release(const typename * p) \
{ \
	assert(p->ref_count_); \
	if (--(p->ref_count_)==0) \
		delete const_cast<typename*>(p); \
} \
typedef boost::intrusive_ptr<typename> ptr_base_name##_ptr; \
typedef boost::intrusive_ptr<const typename> ptr_base_name##_const_ptr;

///////////////////////////////////////////////////////////////////////////////////////
////// Utils
///////////////////////////////////////////////////////////////////////////////////////
JAMLIB_EXPORT int digit_to_num(char digit);
inline bool jam_is_digit(char digit)
{
	switch(digit)
	{
	case '0':		
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '9':
		return true;
	default:
		return false;
	}
}

//This macro creates a dynamic-sized stack array.
//TODO: add backup support for platforms without _alloca.
#define DYN_STACK_ARRAY(type,name,size) type *name=(type*)_alloca(size*sizeof(type));

#endif //JAM_H
